home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
4_0
/
MANDLE_C
/
MANDCRAW.C
< prev
Wrap
Text File
|
1990-05-06
|
6KB
|
232 lines
/* Copyright 1988,1989 by Scott Sherman and John Gossman
The following C code is for a fast Mandelbrot Algorithm
called Contour Crawling, invented by Scott Sherman in 1986 while a
math student at Western Washington Univ. The algorithm works by
scanning across the Mandelbrot Set point by point, looking
for regions of the same color. Once a "Contour" is detected, the
algorithm bounces back and forth along the boundary of the contour
until it finds its way back to its starting point, and then fills the
interior. Intuitively and in practice it is far more efficient than
the normal pixel by pixel method or Mariani's Method. The following
code should demonstrate that it is also simple. Scott and I (John
Gossman) have written an article about Contour Crawling that covers
the theoretical aspects and such concerns as "Islands", the connected
nature of the level sets around the Mandelbrot Set, and the practical
issues of Contour Crawling on a discrete lattice. I will post this
article somewhere soon, and leave a note here about getting hold of
it. The best argument is to code up a version of this program and
look at the results. Another nice thing is that all the optimization
tricks for calculating the count (assembly, fixed-point etc.) can still
be applied to this method in order to further increase the speed.
*/
/*
Keywords to be defined :
MINX, ; These four define the resolution
MINY,
MAXX,
MAXY,
BIGGESTCOUNT, ; the maximum iterations for GetCount
BLANK, ; normally 0
LIMIT ; Use 4 or 5. Used to recognize contours.
GETPIXEL(), ; A function to read a pixel value
PUTPIXEL(), ; A function to set a pixel value
*/
#define MINX 0
#define MINY 0
#define MAXX 500
#define MAXY 400
#define BIGGESTCOUNT 255
#define BLANK 0
#define LIMIT 4
extern Boolean HALT;
int maxcount;
int new;
double xr[MAXX+1];
double yr[MAXY+1];
int color[BIGGESTCOUNT];
/* (x_coord,y_coord) contain the screen coordinates of the point
return the count of the point */
int GetCount(x_coord,y_coord)
int x_coord,y_coord;
{
double x,y;
double cx,cy;
double x2,y2;
int count;
count = 1;
x = xr[x_coord];y = yr[y_coord];
cx = x; cy = y;
x2 = x*x;y2 = y*y;
while ((x2 + y2 < 4) && (count < maxcount))
{
y = 2*x*y + cy;
x = x2-y2 + cx;
x2 = x*x;
y2 = y*y;
count = count + 1;
}
return (count);
}
/* (x,y) contain the screen coordinates of a point
return its color
if the point is off the screen, return BLANK
if the point was freshly calculated, display it & new = TRUE
*/
int _GetColor(x,y)
int x,y;
{
int temp,GetCount();
int GETPIXEL();
if ((x<MINX) || (x>MAXX) || (y<MINY) || (y>MAXY))
return (BLANK);
temp = GETPIXEL(x,y);
if (temp == BLANK)
{
new = TRUE;
temp = GetCount(x,y);
temp = color[temp];
PUTPIXEL(x,y,temp);
}
else new = FALSE;
return (temp);
}
/* (x,y) contain the screen coordinates of the point
If this point hasn't been calculated before, return TRUE */
int IsBlank(x,y)
int x,y;
{
if ((x<MINX) || (x>=MAXX) || (y<MINY) || (y>=MAXY))
return FALSE;
return (GETPIXEL(x,y) == BLANK);
}
/* (x,y) contain the screen coordinates of a point on a contour
'thecount' contains the value of the contour
if 'fill' is FALSE, crawl the region
if 'fill' is TRUE, fill the region */
void Crawl(x,y,thecount,fill)
int x,y;
int thecount;
int fill;
{
int xinc,yinc; /* direction to travel */
int firstx,firsty; /* the starting & ending point */
int done; /* we've reached the end */
int _GetColor(),IsBlank();
firstx = x;
firsty = y;
xinc = 1;
done = FALSE;
while (!done)
{
if (HALT) goto out;
if (_GetColor(x+xinc,y) == thecount)
{
x = x + xinc;
yinc = -xinc;
done = (x==firstx) && (y==firsty);
if (fill && IsBlank(x-yinc,y))
FillLine(x-yinc,y,yinc,thecount);
}
else yinc = xinc;
if (!done && (_GetColor(x,y+yinc) == thecount))
{
y = y + yinc;
xinc = yinc;
done = (x==firstx) && (y==firsty);
if (fill && IsBlank(x-yinc,y))
FillLine(x-yinc,y,yinc,thecount);
}
else xinc = -yinc;
}
if (!fill)
Crawl(firstx,firsty,thecount,TRUE);
out:
;
}
/* (leftx,topy) contain the real coordinates of the upper left
corner of the region - 'gap' is the length of a side
calculate the cooresponding region of the Mandelbrot Set */
DisplaySet(leftx,topy,gap)
double leftx,topy,gap;
{
double smallgap; /* real width of a pixel */
int last,count; /* last count & present count */
int edge,edgex,edgey; /* screen coords of edge of contour */
int x,y; /* current screen coordinates */
int _GetColor();
smallgap = gap/MAXY;
for (x=MINX; x<=MAXX; x++)
xr[x] = leftx + (x-MINX) * smallgap;
for (y=MINY; y<=MAXY; y++)
yr[y] = topy - (y-MINY) * smallgap;
edge = 0;
last = BLANK;
for (x=MINX; x<=MAXX; x++)
{
for (y=MINY; y<=MAXY; y++)
{
if (HALT) goto out;
count = _GetColor(x,y);
if (count == last)
edge++;
else {
last = count;
edge = 0;
edgex = x;
edgey = y;
}
if (new && edge>=LIMIT)
Crawl(edgex,edgey,count,FALSE);
}
edge = 0;
last = BLANK;
}
out:
;
}
/* To make contour crawling faster and generate prettier pictures
with less "noise" near the edge of the Mandelbrot Set, you can
combine level sets. The following fragment combines every other
band on a 16 color system. A more sophisticated approach is to
combine bands logarithmically, so that outer bands do not get
combined and narrow bands near the MandelBrot set get clumped
together in groups of hundreds. IMPORTANT: This not only makes the
algorithm faster it makes better looking pictures.
I removed this extensive color stuff because the Mac has 8-bit graphics */
/* a sample of how the bands could be combined */
GENERATECOUNTS(color,maxcount)
int color[];
int maxcount;
{
int i;
for (i=0; i<maxcount; i++)
color[i] = (i % 255);
}